#include "netclient.h"
#include "../model/datacenter.h"
#include <QNetworkReply>
namespace network
{
NetClient::NetClient(model::DataCenter *dataCenter) : _dataCenter(dataCenter) {}

void NetClient::initWebsocket()
{
    // 1. 设置信号槽
    connect(&_webSocketClient, &QWebSocket::connected, this,
            [=]()
            {
                LOG() << "websocket 连接成功！";
                // 在 websocket 连接成功后，发送身份认证信息
                // sendAuth();
            });

    connect(&_webSocketClient, &QWebSocket::disconnected, this, [=]() { LOG() << "websocket 连接断开！"; });

    connect(&_webSocketClient, &QWebSocket::errorOccurred, this,
            [=](QAbstractSocket::SocketError error) { LOG() << "websocket 连接出错！" << error; });

    connect(&_webSocketClient, &QWebSocket::textMessageReceived, this,
            [=](const QString &message) { LOG() << "websocket 收到文本消息！" << message; });

    connect(&_webSocketClient, &QWebSocket::binaryMessageReceived, this,
            [=](const QByteArray &byteArray)
            {
                LOG() << "websocket 收到二进制消息！";
                MicroIMS::NotifyMessage notifyMessage;
                notifyMessage.deserialize(&_serializer, byteArray);
                handleWsResponse(notifyMessage);
            });

    // 2. 和服务器真正建立连接
    _webSocketClient.open(WEBSOCKET_URL);
}

void NetClient::ping()
{
    QNetworkRequest httpReq;
    httpReq.setUrl(QUrl(HTTP_URL + "/ping"));

    QNetworkReply *httpResp = _httpClient.get(httpReq);
    connect(httpResp, &QNetworkReply::finished, this,
            [=]()
            // 这个表达式在响应回来时触发
            {
                if (httpResp->error() != QNetworkReply::NoError)
                {
                    // 请求失败
                    LOG() << "HTTP 请求失败！" << httpResp->errorString();
                    httpResp->deleteLater();
                    return;
                }
                // 获取到响应的 body
                QByteArray body = httpResp->readAll();
                LOG() << "响应内容：" << body;
                httpResp->deleteLater();
            });
}

void NetClient::sendAuth()
{
    MicroIMS::ClientAuthenticationReq req;
    req.setRequestId(makeRequestId());
    req.setRequestId(_dataCenter->getLoginSessionId());
    QByteArray body = req.serialize(&_serializer);
    _webSocketClient.sendBinaryMessage(body);
    LOG() << "[WS身份认证] requestId=" << req.requestId() << ",loginSessionId=" << req.sessionId();
}

QString NetClient::makeRequestId() { return "R" + QUuid::createUuid().toString().sliced(25, 12); }

QNetworkReply *NetClient::sendHttpRequest(const QString &apiPath, const QByteArray &body)
{
    QNetworkRequest httpReq;
    httpReq.setUrl(QUrl(HTTP_URL + apiPath));
    httpReq.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-protobuf");

    QNetworkReply *httpResp = _httpClient.post(httpReq, body);
    return httpResp;
}

// 这个函数实现具体的网络通信
void NetClient::getMyself(const QString &loginSessionId)
{
    // 1. 构造 HTTP 请求的 body 部分
    MicroIMS::GetUserInfoReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    QByteArray body = req.serialize(&_serializer);
    LOG() << "[获取个人信息] 发送请求 requestId=" << req.requestId() << ",loginSessionId=" << loginSessionId;

    // 2. 构造 HTTP 请求并发送出去
    QNetworkReply *httpResp = sendHttpRequest("/service/user/get_user_info", body);

    // 3. 通过信号槽，获取到当前的响应，finished 信号表示响应已经回到客户端了
    connect(httpResp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 先处理响应对象
                bool ok;
                QString reason;
                auto resp = handleHttpResponse<MicroIMS::GetUserInfoRsp>(httpResp, &ok, &reason);

                // b) 判定响应是否正确
                if (!ok)
                {
                    LOG() << "[获取个人信息] 出错！requestId=" << req.requestId() << "reason=" << reason;
                    return;
                }

                // c) 把响应的数据保存到 DataCenter 中
                _dataCenter->resetMyself(resp);

                // d) 通知调用逻辑，响应已经处理完成了，通过信号槽进行通知
                emit _dataCenter->getMyselfDone();

                // e) 打印日志
                LOG() << "[获取个人信息] 处理响应 requestId=" << req.requestId();
            });
}

void NetClient::getFriendList(const QString &loginSessionId)
{
    // 1. 通过 protobuf 构造 body
    MicroIMS::GetFriendListReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    QByteArray body = req.serialize(&_serializer);
    LOG() << "[获取好友列表] 发送请求 requestId=" << req.requestId() << ", loginSessionId=" << loginSessionId;

    // 2. 发送 HTTP 请求
    QNetworkReply *httpResp = this->sendHttpRequest("/service/friend/get_friend_list", body);

    // 3. 处理响应
    connect(httpResp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok = false;
                QString reason;
                auto friendListResp = this->handleHttpResponse<MicroIMS::GetFriendListRsp>(httpResp, &ok, &reason);

                // b) 判定响应是否正确
                if (!ok)
                {
                    LOG() << "[获取好友列表] 失败！requestId=" << req.requestId() << ",reason=" << reason;
                    return;
                }

                // c) 把结果保存在 DataCenter 中
                _dataCenter->resetFriendList(friendListResp);

                // d) 通知界面处理完毕
                emit _dataCenter->getFriendListDone();

                // e) 打印日志
                LOG() << "[获取好友列表] 处理响应 requestId=" << req.requestId();
            });
}

void NetClient::getChatSessionList(const QString &loginSessionId)
{
    // 1. 通过 protobuf 构造 body
    MicroIMS::GetChatSessionListReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    QByteArray body = req.serialize(&_serializer);
    LOG() << "[获取会话列表] 发送请求 requestId=" << req.requestId() << ",loginSessionId=" << loginSessionId;

    // 2. 发送 HTTP 请求
    QNetworkReply *httpResp = this->sendHttpRequest("/service/friend/get_chat_session_list", body);

    // 3. 处理响应
    connect(httpResp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::GetChatSessionListRsp>(httpResp, &ok, &reason);

                // b) 判定响应是否正确
                if (!ok)
                {
                    LOG() << "[获取会话列表] 失败！reason=" << reason;
                    return;
                }

                // c) 把结果保存在 DataCenter 中
                _dataCenter->resetChatSessionList(pbResp);

                // d) 通知界面处理完毕
                emit _dataCenter->getChatSessionListDone();

                // e) 打印日志
                LOG() << "[获取会话列表] 处理响应完毕！ requestId=" << req.requestId();
            });
}

void NetClient::getApplyList(const QString &loginSessionId)
{
    // 1. 通过 protobuf 构造 body
    MicroIMS::GetPendingFriendEventListReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    QByteArray body = req.serialize(&_serializer);
    LOG() << "[获取好友申请列表] 发送请求 requestId=" << req.requestId() << ",loginSessionId=" << loginSessionId;

    // 2. 发送 HTTP 请求
    QNetworkReply *httpResp = this->sendHttpRequest("/service/friend/get_pending_friend_events", body);

    // 3. 处理响应
    connect(httpResp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::GetPendingFriendEventListRsp>(httpResp, &ok, &reason);

                // b) 判定响应是否正常
                if (!ok)
                {
                    LOG() << "[获取好友申请列表] 失败！reason=" << reason;
                    return;
                }

                // c) 把结果保存在 DataCenter 中
                _dataCenter->resetApplyList(pbResp);

                // d) 通知界面处理完毕
                emit _dataCenter->getApplyListDone();

                // e) 打印日志
                LOG() << "[获取好友申请列表] 处理响应完毕！ requestId=" << req.requestId();
            });
}

void NetClient::getRecentMessageList(const QString &loginSessionId, const QString &chatSessionId, bool updateUI)
{
    // 1. 通过 protobuf 构造请求 body
    MicroIMS::GetRecentMsgReq req;
    req.setRequestId(makeRequestId());
    req.setSessionId(loginSessionId);
    req.setChatSessionId(chatSessionId);
    req.setMsgCount(50); // 这里固定显示最近 50 条历史记录

    QByteArray body = req.serialize(&_serializer);
    LOG() << "[获取最近消息] 发送请求 requestId=" << req.requestId() << ",loginSessionId=" << loginSessionId
          << ",chatSessionId=" << chatSessionId;

    // 2. 发送 http 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/message_storage/get_recent", body);

    // 3. 处理响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应，反序列化
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::GetRecentMsgRsp>(resp, &ok, &reason);

                // b) 判定响应是否出错
                if (!ok)
                {
                    LOG() << "[获取最近消息] 失败！reason=" << reason;
                    return;
                }
                // c) 把拿到的数据保存到 DataCenter 中
                _dataCenter->resetRecentMessageList(chatSessionId, pbResp);

                // d) 发送信号，告知界面进行更新
                if (updateUI)
                {
                    emit _dataCenter->getRecentMessageListDone(chatSessionId);
                }
                else
                {
                    emit _dataCenter->getRecentMessageListDoneNoUI(chatSessionId);
                }
            });
}

void NetClient::sendMessage(const QString &loginSessionId, const QString &chatSessionId, model::MessageType messageType,
                            const QByteArray &content, const QString &extraInfo)
{
    // 1. 通过 protobuf 构造 body
    MicroIMS::NewMessageReq pbReq;
    pbReq.setRequestId(makeRequestId());
    pbReq.setSessionId(loginSessionId);
    pbReq.setChatSessionId(chatSessionId);

    // 构造 messageContent
    MicroIMS::MessageContent messageContent;
    if (messageType == model::MessageType::TEXT_TYPE)
    {
        messageContent.setMessageType(MicroIMS::MessageTypeGadget::STRING);

        MicroIMS::StringMessageInfo stringMessageInfo;
        stringMessageInfo.setContent(content);
        messageContent.setStringMessage(stringMessageInfo);
    }
    else if (messageType == model::MessageType::IMAGE_TYPE)
    {
        messageContent.setMessageType(MicroIMS::MessageTypeGadget::IMAGE);

        MicroIMS::ImageMessageInfo imageMessageInfo;
        imageMessageInfo.setFileId(""); // fileId 在服务器存储时生成，这里暂时设置为""
        imageMessageInfo.setImageContent(content);
        messageContent.setImageMessage(imageMessageInfo);
    }
    else if (messageType == model::MessageType::FILE_TYPE)
    {
        messageContent.setMessageType(MicroIMS::MessageTypeGadget::FILE);

        MicroIMS::FileMessageInfo fileMessageInfo;
        fileMessageInfo.setFileId(""); // fileId 在服务器存储时生成，这里暂时设置为""
        fileMessageInfo.setFileSize(content.size());
        fileMessageInfo.setFileName(extraInfo);
        fileMessageInfo.setFileContents(content);
        messageContent.setFileMessage(fileMessageInfo);
    }
    else if (messageType == model::MessageType::SPEECH_TYPE)
    {
        messageContent.setMessageType(MicroIMS::MessageTypeGadget::SPEECH);

        MicroIMS::SpeechMessageInfo speechMessageInfo;
        speechMessageInfo.setFileId(""); // fileId 在服务器存储时生成，这里暂时设置为""
        speechMessageInfo.setFileContents(content);
        messageContent.setSpeechMessage(speechMessageInfo);
    }
    else
    {
        LOG() << "错误的消息类型！messageType=" << messageType;
    }
    pbReq.setMessage(messageContent);

    // 序列化
    QByteArray body = pbReq.serialize(&_serializer);
    LOG() << "[发送消息] 发送请求 requestId=" << pbReq.requestId() << ",loginSessionId=" << pbReq.sessionId()
          << ",chatSessionId=" << pbReq.chatSessionId() << ",messageType=" << pbReq.message().messageType();

    // 发送 HTTP 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/message_transmit/new_message", body);

    // 处理 HTTP 响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 针对响应结果进行解析
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::NewMessageRsp>(resp, &ok, &reason);
                if (!ok)
                {
                    LOG() << "[发送消息] 处理出错！reason=" << reason;
                    return;
                }
                // c) 此处只记录 "成功失败" 不需要把内容写入到 DataCenter 中

                // d) 通知调用者，响应处理完毕
                emit _dataCenter->sendMessageDone(messageType, content, extraInfo);

                // e) 打印日志
                LOG() << "[发送消息] 响应处理完毕！requestId=" << pbResp->requestId();
            });
}

void NetClient::handleWsResponse(MicroIMS::NotifyMessage &notifyMessage)
{
    if (notifyMessage.notifyType() == MicroIMS::NotifyTypeGadget::NotifyType::CHAT_MESSAGE_NOTIFY)
    {
        // 收到消息
        // 1. 把 pb 中的 MessageInfo 转成客户端自己的 Message
        model::Message message;
        message.load(notifyMessage.newMessageInfo().messageInfo());

        // 2. 针对自己的 message 做进一步处理
        handleWsMessage(message);
    }
    else if (notifyMessage.notifyType() == MicroIMS::NotifyTypeGadget::NotifyType::CHAT_SESSION_CREATE_NOTIFY)
    {
        // 创建新会话通知
    }
    else if (notifyMessage.notifyType() == MicroIMS::NotifyTypeGadget::NotifyType::FRIEND_ADD_APPLY_NOTIFY)
    {
        // 添加好友申请通知
        model::UserInfo userInfo;
        userInfo.load(notifyMessage.friendAddApply().userInfo());
        handleWsAddFriendApply(userInfo);
    }
    else if (notifyMessage.notifyType() == MicroIMS::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY)
    {
        // 添加好友申请处理结果通知
    }
    else if (notifyMessage.notifyType() == MicroIMS::NotifyTypeGadget::NotifyType::FRIEND_REMOVE_NOTIFY)
    {
        // 删除好友通知
        const QString &userId = notifyMessage.friendRemove().userId();
        handleWsRemoveFriend(userId);
    }
}

void NetClient::handleWsMessage(const model::Message &message)
{
    QList<model::Message> *messageList = _dataCenter->getRecentMessageList(message.chatSessionId);
    if (messageList == nullptr)
    {
        // 如果当前这个消息所属的会话的消息列表没有在本地加载，通过网络加载消息列表
        connect(_dataCenter, &model::DataCenter::getRecentMessageListDoneNoUI, this, &NetClient::receiveMessage,
                Qt::UniqueConnection);
        _dataCenter->getRecentMessageListAsync(message.chatSessionId, false);
    }
    else
    {
        // 如果当前这个消息所属的会话的消息列表有已经本地加载了，直接尾插消息
        messageList->push_back(message);
        this->receiveMessage(message.chatSessionId);
    }
}

void NetClient::handleWsRemoveFriend(const QString &userId)
{
    // 1. 删除 DataCenter 好友列表的数据
    _dataCenter->removeFriend(userId);
    // 2. 通知界面变化，更新好友/会话列表
    emit _dataCenter->deleteFriendDone();
}

void NetClient::handleWsAddFriendApply(const model::UserInfo &userInfo)
{
    // 1. 将这个数据添加到 DataCenter 的 好友申请列表 中
    QList<model::UserInfo> *applyList = _dataCenter->getApplyList();
    if (applyList == nullptr)
    {
        LOG() << "客户端没有加载到好友申请列表！";
        return;
    }
    // 把新元素添加到列表尾部
    applyList->push_back(userInfo);

    // 2. 通知界面更新
    emit _dataCenter->receiveFriendApplyDone();
}

void NetClient::receiveMessage(const QString &chatSessionId)
{
    // 先判定当前收到消息的会话，是否是用户正在选中的会话
    if (chatSessionId == _dataCenter->getCurrentChatSessionId())
    {
        // 如果是，就需要将消息显示到消息展示区，并更新会话列表的消息预览
        const model::Message &lastMessage = _dataCenter->getRecentMessageList(chatSessionId)->back();
        // 通过信号让 NetClient 通知界面
        emit _dataCenter->receiveMessageDone(lastMessage);
    }
    else
    {
        // 如果不是，只需要更新会话列表的消息预览，并更新 未读消息数目
        _dataCenter->addUnread(chatSessionId);
    }
    // 统一更细会话列表的消息预览
    emit _dataCenter->updateLastMessage(chatSessionId);
}

void NetClient::changeNickname(const QString &loginSessionId, const QString &nickname)
{
    // 1. 通过 protobuf 构造请求 body
    MicroIMS::SetUserNicknameReq pbReq;
    pbReq.setRequestId(makeRequestId());
    pbReq.setSessionId(loginSessionId);
    pbReq.setNickname(nickname);
    QByteArray body = pbReq.serialize(&_serializer);
    LOG() << "[修改用户昵称] 发送请求 requestId=" << pbReq.requestId() << ",loginSessionId=" << pbReq.sessionId()
          << ",nickname=" << pbReq.nickname();

    // 2. 发送 HTTP 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/user/set_nickname", body);

    // 3. 处理响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::SetUserNicknameRsp>(resp, &ok, &reason);

                // b) 判断响应是否出错
                if (!ok)
                {
                    LOG() << "[修改用户昵称] 出错！reason=" << reason;
                    return;
                }

                // c) 把数据设置到 DataCenter 里
                _dataCenter->resetNickname(nickname);

                // d) 发送信号，通知调用者处理完毕
                emit _dataCenter->changeNicknameDone();

                // e) 打印日志
                LOG() << "[修改用户昵称] 处理响应完毕！requestId=" << pbResp->requestId();
            });
}

void NetClient::changeDescription(const QString &loginSessionId, const QString &desc)
{
    // 1. 通过 protobuf 构造请求
    MicroIMS::SetUserDescriptionReq pbReq;
    pbReq.setRequestId(makeRequestId());
    pbReq.setSessionId(loginSessionId);
    pbReq.setDescription(desc);
    QByteArray body = pbReq.serialize(&_serializer);
    LOG() << "[修改签名] 发送请求 requestId=" << pbReq.requestId() << ",loginSessionId=" << pbReq.sessionId()
          << ",desc=" << pbReq.description();

    // 2. 发送 HTTP 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/user/set_description", body);

    // 3. 处理响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::SetUserDescriptionRsp>(resp, &ok, &reason);

                // b) 判定响应是否成功
                if (!ok)
                {
                    LOG() << "[修改签名] 响应失败！reason=" << reason;
                    return;
                }

                // c) 把得到的结果，保存到 DataCenter 中
                _dataCenter->resetDescription(desc);

                // d) 发送信号，通知修改完成
                emit _dataCenter->changeDescriptionDone();

                // e) 打印日志
                LOG() << "[修改签名] 响应完成！requestId=" << pbResp->requestId();
            });
}

void NetClient::getVerifyCode(const QString &phone)
{
    // 1. 构造请求 body
    MicroIMS::PhoneVerifyCodeReq pbReq;
    pbReq.setRequestId(makeRequestId());
    pbReq.setPhoneNumber(phone);
    QByteArray body = pbReq.serialize(&_serializer);
    LOG() << "[获取手机验证码] 发送请求 requestId=" << pbReq.requestId() << ",phone=" << phone;

    // 2. 发送 HTTP 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/user/get_phone_verify_code", body);

    // 3. 处理响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::PhoneVerifyCodeRsp>(resp, &ok, &reason);

                // b) 判定响应是否成功
                if (!ok)
                {
                    LOG() << "[获取手机验证码] 失败！reason=" << reason;
                    return;
                }

                // c) 保存数据到 DataCenter
                _dataCenter->resetVerifyCodeId(pbResp->verifyCodeId());

                // d) 发送信号，通知调用者
                emit _dataCenter->getVerifyCodeDone();

                // e) 打印日志
                LOG() << "[获取手机验证码] 响应完成 requestId=" << pbResp->requestId();
            });
}

void NetClient::changePhone(const QString &loginSessionId, const QString &phone, const QString &verifyCodeId,
                            const QString &verifyCode)
{
    // 1. 构造请求 body
    MicroIMS::SetUserPhoneNumberReq pbReq;
    pbReq.setRequestId(makeRequestId());
    pbReq.setSessionId(loginSessionId);
    pbReq.setPhoneNumber(phone);
    pbReq.setPhoneVerifyCodeId(verifyCodeId);
    pbReq.setPhoneVerifyCode(verifyCode);
    QByteArray body = pbReq.serialize(&_serializer);
    LOG() << "[修改手机号] 发送请求 requestId=" << pbReq.requestId() << ",loginSessionId=" << pbReq.sessionId()
          << ",phone" << pbReq.phoneNumber() << ",verifyCodeId=" << pbReq.phoneVerifyCodeId() << ",verifyCode"
          << pbReq.phoneVerifyCode();

    // 2. 发送 HTTP 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/user/set_phone", body);

    // 3. 处理响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::SetUserPhoneNumberRsp>(resp, &ok, &reason);

                // b) 判定响应是否正确
                if (!ok)
                {
                    LOG() << "[修改手机号] 响应失败！reason=" << reason;
                    return;
                }

                // c) 把结果保存到 DataCenter 中
                _dataCenter->resetPhone(phone);

                // d) 发送信号，通知调用者处理完毕
                emit _dataCenter->changePhoneDone();

                // e) 打印日志
                LOG() << "[修改手机号] 相应完成 requestId=" << pbResp->requestId();
            });
}

void NetClient::changeAvatar(const QString &loginSessionId, const QByteArray &avatar)
{
    // 1. 构造请求 body
    MicroIMS::SetUserAvatarReq pbReq;
    pbReq.setRequestId(makeRequestId());
    pbReq.setSessionId(loginSessionId);
    pbReq.setAvatar(avatar);
    QByteArray body = pbReq.serialize(&_serializer);
    LOG() << "[修改头像] 发送请求 requestId=" << pbReq.requestId() << ",loginSessionId=" << pbReq.sessionId();

    // 2. 发送 HTTP 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/user/set_avatar", body);

    // 3. 处理响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::SetUserAvatarRsp>(resp, &ok, &reason);

                // b) 判定响应结果是否正确
                if (!ok)
                {
                    LOG() << "[修改头像] 响应出错！reason=" << reason;
                    return;
                }

                // c) 把数据保存到 DataCenter 中
                _dataCenter->resetAvatar(avatar);

                // d) 发送信号
                emit _dataCenter->changeAvatarDone();

                // e) 打印日志
                LOG() << "[修改头像] 响应完成 requestId=" << pbResp->requestId();
            });
}

void NetClient::deleteFriend(const QString &loginSessionId, const QString &userId)
{
    // 1. 构造请求 body
    MicroIMS::FriendRemoveReq pbReq;
    pbReq.setRequestId(makeRequestId());
    pbReq.setSessionId(loginSessionId);
    pbReq.setPeerId(userId);
    QByteArray body = pbReq.serialize(&_serializer);
    LOG() << "[删除好友] 发送请求 requestId=" << pbReq.requestId() << ",loginSessionId=" << pbReq.sessionId()
          << ",userId=" << pbReq.peerId();

    // 2. 发送 HTTP 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/friend/remove_friend", body);

    // 3. 处理响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::FriendRemoveRsp>(resp, &ok, &reason);

                // b) 判定响应是否正确
                if (!ok)
                {
                    LOG() << "[删除好友] 响应失败！rason=" << reason;
                    return;
                }
                // d) 发送信号，通知调用者删除好友完毕
                emit _dataCenter->deleteFriendDone();

                // e) 打印日志
                LOG() << "[删除好友] 响应完毕 requestId=" << pbReq.requestId();
            });
}

void NetClient::addFriendApply(const QString &loginSessionId, const QString &userId)
{
    // 1. 构造请求 body
    MicroIMS::FriendAddReq pbReq;
    pbReq.setRequestId(makeRequestId());
    pbReq.setSessionId(loginSessionId);
    pbReq.setRespondentId(userId);
    QByteArray body = pbReq.serialize(&_serializer);
    LOG() << "[添加好友申请] 发送请求 requestId=" << pbReq.requestId() << ",loginSessionId=" << pbReq.sessionId()
          << ",userId" << userId;

    // 2. 发送 HTTP 请求
    QNetworkReply *resp = this->sendHttpRequest("/service/friend/add_friend_apply", body);

    // 3. 处理响应
    connect(resp, &QNetworkReply::finished, this,
            [=]()
            {
                // a) 解析响应
                bool ok = false;
                QString reason;
                auto pbResp = this->handleHttpResponse<MicroIMS::FriendAddRsp>(resp, &ok, &reason);

                // b) 判断响应是否正确
                if (!ok)
                {
                    LOG() << "[添加好友申请] 响应失败！reason=" << reason;
                    return;
                }

                // c） 此时不需要保存数据

                // d) 发送信号通知调用者
                emit _dataCenter->addFriendApplyDone();

                // e) 打印日志
                LOG() << "[添加好友申请] 响应完毕 requestId=" << pbResp->requestId();
            });
}
} // namespace network
